package lbs

import (
	"errors"
	"fmt"
	"strings"
)

var (
	InvalidLocation = errors.New("无效的坐标")
)

type Boundary struct {
	// 纬度
	Lat float64 `json:"lat"`
	// 经度
	Lng float64 `json:"lng"`
	// 搜索半径
	Radius uint `json:"radius"`
	// 是否扩大
	AutoExtend bool `json:"auto_extend"`
}

// Format 检索格式化
func (b *Boundary) Format() string {
	e := 0
	if b.AutoExtend {
		e = 1
	}
	return fmt.Sprintf("nearby(%f,%f,%d,%d)", b.Lat, b.Lng, b.Radius, e)
}

// Location 坐标
type Location struct {
	// 纬度
	Lat float64 `json:"lat"`
	// 经度
	Lng float64 `json:"lng"`
}

// Format 检索格式化
func (l *Location) Format() string {
	return fmt.Sprintf("%f,%f", l.Lat, l.Lng)
}

type AdInfo struct {
	// 行政划区代码
	AdCode uint `json:"adcode"`
	// 国家
	Nation string `json:"nation"`
	// 省
	Province string `json:"province"`
	// 市
	City string `json:"city"`
	// 区
	District string `json:"district"`
}

// GetCode 获取划区代码
func (a *AdInfo) GetCode() string {
	return fmt.Sprintf("%d", a.AdCode)
}

// PlaceSearchReq 地点检索 请求
type PlaceSearchReq struct {
	// 搜索关键字
	Keyword string `json:"keyword"`
	// 范围
	Boundary *Boundary `json:"boundary"`
	// 筛选条件
	Filter string `json:"filter"`
	// 排序
	OrderBy string `json:"order_by"`
	// page size
	PageSize uint `json:"page_size"`
	// page no
	PageIndex uint `json:"page_no"`
}

// PlaceSearchItem 地址信息
type PlaceSearchItem struct {
	// POI 唯一标识
	Id string `json:"id"`
	// POI 名称
	Title string `json:"title"`
	// 地址
	Address string `json:"address"`
	// 电话
	Tel string `json:"tel"`
	// 分类
	Category string `json:"category"`
	// 类型
	Type uint8 `json:"type"`
	// 坐标
	Location *Location `json:"location"`
	// 距离
	Distance float64 `json:"_distance"`
	// 行政划区
	AdInfo *AdInfo `json:"ad_info"`
}

// GetType 获取地址类型
func (p *PlaceSearchItem) GetType() string {
	switch p.Type {
	case 1:
		return "公交站"
	case 2:
		return "地铁站"
	case 3:
		return "公交线路"
	case 4:
		return "行政划区"
	default:
		return "普通地址"
	}
}

// PlaceSearchReply 地点检索 返回
type PlaceSearchReply struct {
	// total
	Count int                `json:"Count"`
	Data  []*PlaceSearchItem `json:"data"`
}

// GeoAddressCoderReq 逆地址解析 请求
type GeoAddressCoderReq struct {
	// 经纬度坐标
	Location *Location `json:"location"`
	// 是否返回周边地址
	GetPoi bool `json:"get_poi"`
	// 周边 POI列表控制参数
	PoiPotions string `json:"poi_potions"`
}

// FormattedAddress 描述地址
type FormattedAddress struct {
	// 地址描述
	Recommend string `json:"recommend"`
	// 粗略地址描述
	Rough string `json:"rough"`
}

// AddressComponent 地址部件
type AddressComponent struct {
	// 国家
	Nation string `json:"nation"`
	// 省
	Province string `json:"province"`
	// 市
	City string `json:"city"`
	// 区
	District string `json:"district"`
	// street
	Street string `json:"street"`
	// 门牌号
	StreetNumber string `json:"street_number"`
}

// AdInfoV2 行政区信息
type AdInfoV2 struct {
	// 国家代码
	NationCode string `json:"nation_code"`
	// 行政区划代码
	AdCode string `json:"adcode"`
	// 城市编码
	CityCode string `json:"city_code"`
	// 行政区划名
	Name string `json:"name"`
	// 地址坐标
	Location *Location `json:"location"`
	// 国家
	Nation string `json:"nation"`
	// 省
	Province string `json:"province"`
	// 市
	City string `json:"city"`
	// 区
	District string `json:"district"`
}

// GetCityCode 获取正常城市编码
func (a *AdInfoV2) GetCityCode() string {
	if strings.HasPrefix(a.CityCode, a.NationCode) {
		return strings.Replace(a.CityCode, a.NationCode, "", 1)
	}
	return a.CityCode
}

// AddressCoder 逆地址解析结果
type AddressCoder struct {
	// 地址
	Address string `json:"address"`
	// 描述性地址
	FormattedAddress *FormattedAddress `json:"formatted_address"`
	// 行政区信息
	AdInfo *AdInfoV2 `json:"ad_info"`
	// 机制部件
	AddressComponent *AddressComponent `json:"address_component"`
}

// GeoAddressCoderReply 逆地址解析 返回
type GeoAddressCoderReply struct {
	// 请求唯一标识
	RequestId string `json:"request_id"`
	// result
	Result *AddressCoder `json:"result"`
}

// GeoLocationCoderReq 地址解析 请求
type GeoLocationCoderReq struct {
	// 地址
	Address string `json:"address"`
	// 所在城市
	Region string `json:"region"`
}

type AdInfoV3 struct {
	AdCode string `json:"adcode"`
}

// LocationCoder 地址解析结果
type LocationCoder struct {
	// 关键地址，地点
	Title string `json:"title"`
	// 坐标
	Location *Location `json:"location"`
	// 解析后地址部件
	AddressComponents *AddressComponent `json:"address_components"`
	// 行政划区信息
	AdInfo *AdInfoV3 `json:"ad_info"`
	// 可信度
	Reliability int `json:"reliability"`
	// 经度级别
	Level int `json:"level"`
}

// GeoLocationCoderReply 地址解析 返回
type GeoLocationCoderReply struct {
	// 请求唯一标识
	RequestId string `json:"request_id"`
	// result
	Result *LocationCoder `json:"result"`
}

// Locations 坐标数组
type LocationArray struct {
	// 起点
	Locations []*Location `json:"locations"`
	// index map
	idxMap map[string]int
}

func (la *LocationArray) Format() string {
	ls := make([]string, len(la.Locations))
	la.idxMap = map[string]int{}
	for idx, l := range la.Locations {
		s := l.Format()
		la.idxMap[s] = idx
		ls[idx] = s
	}
	return strings.Join(ls, ";")
}

func (la *LocationArray) GetIndex(l *Location) (int, error) {
	idx, ok := la.idxMap[l.Format()]
	if !ok {
		return 0, InvalidLocation
	}
	return idx, nil
}

// DistanceMatrixReq 批量地址计算 请求
type DistanceMatrixReq struct {
	// 计算模式
	Mode string `json:"mode"`
	// 起点坐标
	From *LocationArray `json:"from"`
	// 终点坐标
	To *LocationArray `json:"to"`
}

type DistanceMatrixItem struct {
	// 距离，米
	Distance float64 `json:"distance"`
	// 耗时，秒
	Duration int `json:"duration"`
	// 状态
	Status int `json:"status"`
}

// DistanceMatrixElements 数组列
type DistanceMatrixElements struct {
	Elements []*DistanceMatrixItem `json:"elements"`
}

// DistanceMatrixRows 数组行
type DistanceMatrixRows struct {
	// 多点到多点距离计算，结果为二维数组
	Rows []*DistanceMatrixElements `json:"rows"`
}

// DistanceMatrixReply 批量地址计算 返回
type DistanceMatrixReply struct {
	// 起点坐标
	from *LocationArray
	// 终点坐标
	to *LocationArray
	// 结果
	Result *DistanceMatrixRows `json:"result"`
}

// GetItemDistance 获取两点距离信息
func (d *DistanceMatrixReply) GetItemDistance(from *Location, to *Location) (*DistanceMatrixItem, error) {
	if from == nil || to == nil {
		return nil, nil
	}
	row, err := d.from.GetIndex(from)
	if err != nil {
		return nil, err
	}
	col, err := d.to.GetIndex(to)
	if err != nil {
		return nil, err
	}
	if d.Result == nil {
		return nil, nil
	}
	elements := d.Result.Rows[row]
	return elements.Elements[col], nil
}

// LocationsTranslateReq 坐标转换 请求
type LocationsTranslateReq struct {
	Locations *LocationArray `json:"locations"`
	Type      int            `json:"type"`
}

// LocationsTranslateReply 坐标转换 返回
type LocationsTranslateReply struct {
	origins   *LocationArray
	Locations []*Location `json:"locations"`
}

// GetTranslated 获取转换后的坐标
func (lt *LocationsTranslateReply) GetTranslated(l *Location) (*Location, error) {
	if l == nil {
		return nil, nil
	}
	idx, err := lt.origins.GetIndex(l)
	if err != nil {
		return nil, err
	}
	return lt.Locations[idx], nil
}

// IPLocationResult ip 定位结果
type IPLocationResult struct {
	// ip 地址
	IP string `json:"ip"`
	// 定位坐标
	Location *Location `json:"location"`
	// 行政区域信息
	AdInfo *AdInfo `json:"ad_info"`
}

// IPLocationReply ip 定位 返回
type IPLocationReply struct {
	Result *IPLocationResult `json:"result"`
}
